home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’94
/
[√] Distribution Restricted!
/
Christian Ruse
/
Fourier Paper + Apps
/
nih-image154_source.sea
/
V1.54 Source
/
Stacks.p
< prev
next >
Wrap
Text File
|
1994-01-27
|
45KB
|
1,714 lines
unit Stacks;
interface
uses
QuickDraw, Palettes, QDOffscreen, PictUtil, PrintTraps, globals, Utilities, Graphics, Analysis, Camera, file1, file2, filters, sound, lut;
function MakeStackFromWindow: boolean;
procedure MakeStack;
procedure MakeWindowsFromStack;
function AddSlice (update: boolean): boolean;
procedure DeleteSlice;
procedure ShowNextSlice (item: integer);
procedure ShowFirstOrLastSlice (ich: integer);
procedure DoResliceOptions;
procedure Reslice;
procedure Animate;
procedure MakeMovie;
procedure CaptureFrames;
procedure MakeMontage;
procedure ConvertRGBToEightBitColor (Capturing: boolean);
procedure ConvertEightBitColorToRGB;
procedure CaptureColor;
procedure AverageSlices;
procedure ConvertRGBToHSV;
implementation
function MakeStackFromWindow: boolean;
begin
with info^ do begin
StackInfo := StackInfoPtr(NewPtr(SizeOf(StackInfoRec)));
if StackInfo = nil then begin
MakeStackFromWindow := false;
exit(MakeStackFromWindow);
end;
with StackInfo^ do begin
nSlices := 1;
CurrentSlice := 1;
PicBaseH[1] := PicBaseHandle;
SliceSpacing := 0.0;
LoopTime := 0.0;
end;
PictureType := NewPicture;
MakeStackFromWindow := true;
end;
end;
procedure MakeStack;
var
ok, isStack: boolean;
i, result: integer;
TempInfo, SaveInfo: InfoPtr;
str: str255;
begin
if not AllSameSize then begin
PutMessage('All currently open images must be the same size to make a stack.');
exit(MakeStack);
end;
isStack := false;
for i := 1 to nPics do begin
TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
isStack := isStack or (TempInfo^.StackInfo <> nil);
end;
if isStack then begin
PutMessage('All stacks must be closed before making a new stack.');
exit(MakeStack);
end;
if nPics > MaxSlices then begin
NumToString(MaxSlices, str);
PutMessage(concat('Maximun stack size is ', str, ' slices.'));
exit(MakeStack);
end;
StopDigitizing;
DisableDensitySlice;
SelectWindow(PicWindow[1]);
Info := pointer(WindowPeek(PicWindow[1])^.RefCon);
ActivateWindow;
KillRoi;
UnZoom;
if not MakeStackFromWindow then
exit(MakeStack);
with info^ do begin
StackInfo^.nSlices := nPics;
title := 'Stack';
UpdateTitleBar;
Revertable := false;
end;
SaveInfo := Info;
MakingStack := true;
ShowWatch;
for i := 2 to nPics do begin
TempInfo := pointer(WindowPeek(PicWindow[2])^.RefCon);
with TempInfo^ do begin
hunlock(PicBaseHandle);
info^.StackInfo^.PicBaseH[i] := PicBaseHandle;
end;
result := CloseAWindow(PicWindow[2]);
Info := SaveInfo;
end;
with info^ do
UpdateWindowsMenuItem(PixMapSize * StackInfo^.nSlices, title, 1);
MakingStack := false;
end;
function AddSlice (update: boolean): boolean;
var
i: integer;
h: handle;
isRoi: boolean;
begin
with info^, info^.StackInfo^ do begin
AddSlice := false;
if nSlices = MaxSlices then
exit(AddSlice);
isRoi := RoiShowing;
if isRoi then
KillRoi;
h := GetBigHandle(PixMapSize);
if h = nil then begin
PutMessage('Not enough memory available to add a slice to this stack.');
macro := false;
exit(AddSlice);
end;
for i := nSlices downto CurrentSlice + 1 do
PicBaseH[i + 1] := PicBaseH[i];
nSlices := nSlices + 1;
CurrentSlice := CurrentSlice + 1;
PicBaseH[CurrentSlice] := h;
SelectSlice(CurrentSlice);
if Update then begin
SelectAll(false);
DoOperation(EraseOp);
UpdatePicWindow;
end;
UpdateTitleBar;
if isRoi then
RestoreRoi;
WhatToUndo := NothingToUndo;
AddSlice := true;
changes := true;
PictureType := NewPicture;
UpdateWindowsMenuItem(PixMapSize * nSlices, title, PicNum);
end;
end;
procedure DeleteSlice;
var
SliceToDelete, NextSlice, i: integer;
isRoi: boolean;
begin
with info^, info^.StackInfo^ do begin
if nSlices = 1 then begin
WhatToUndo := NothingToUndo;
exit(DeleteSlice);
end;
isRoi := RoiShowing;
if isRoi then
KillRoi;
SetupUndo;
WhatToUndo := UndoSliceDelete;
SliceToDelete := CurrentSlice;
if CurrentSlice = 1 then begin
NextSlice := 2;
WhatToUndo := UndoFirstSliceDelete;
end
else
NextSlice := CurrentSlice - 1;
SelectSlice(NextSlice);
UpdatePicWindow;
DisposHandle(PicBaseH[SliceToDelete]);
for i := SliceToDelete to nSlices - 1 do
PicBaseH[i] := PicBaseH[i + 1];
nSlices := nSlices - 1;
if CurrentSlice <> 1 then
CurrentSlice := CurrentSlice - 1;
UpdateTitleBar;
if isRoi then
RestoreRoi;
changes := true;
UpdateWindowsMenuItem(PixMapSize * nSlices, title, PicNum);
end;
end;
procedure MakeWindowsFromStack;
var
i, ignore, N: integer;
SaveInfo: InfoPtr;
tmp: longint;
function MakeName (i: integer): str255;
var
str: str255;
begin
RealToString(i, 3, 0, str);
if str[1] = ' ' then
str[1] := '0';
if str[2] = ' ' then
str[2] := '0';
MakeName := str;
end;
begin
N := info^.StackInfo^.nSlices;
tmp := SizeOf(PicInfo);
if MaxBlock < (MinFree + info^.ImageSize + (SizeOf(PicInfo) + 2000) * LongInt(N)) then begin
PutMessage('There is not enough memory available to convert this stack to windows.');
exit(MakeWindowsFromStack);
end;
SaveInfo := Info;
KillRoi;
for i := 1 to N - 1 do begin
SelectSlice(1);
info^.StackInfo^.CurrentSlice := 1;
if not Duplicate(MakeName(i), false) then
exit(MakeWindowsFromStack);
info := SaveInfo;
DeleteSlice;
end;
if Duplicate(MakeName(N), false) then begin
info := SaveInfo;
info^.changes := false;
ignore := CloseAWindow(info^.wptr);
end;
end;
procedure ShowNextSlice (item: integer);
var
isRoi: boolean;
begin
with info^, info^.StackInfo^ do begin
if item = NextSliceItem then begin
CurrentSlice := CurrentSlice + 1;
if CurrentSlice > nSlices then
CurrentSlice := nSlices;
end
else begin
CurrentSlice := CurrentSlice - 1;
if CurrentSlice < 1 then
CurrentSlice := 1;
end;
isRoi := RoiShowing;
if isRoi then
KillRoi;
SelectSlice(CurrentSlice);
UpdatePicWindow;
UpdateTitleBar;
WhatToUndo := NothingToUndo;
if isRoi then
RestoreRoi;
end;
end;
procedure ShowFirstOrLastSlice (ich: integer);
var
isRoi: boolean;
begin
with info^, info^.StackInfo^ do begin
if ich = EndKey then
CurrentSlice := nSlices
else
CurrentSlice := 1;
isRoi := RoiShowing;
if isRoi then
KillRoi;
SelectSlice(CurrentSlice);
UpdatePicWindow;
UpdateTitleBar;
WhatToUndo := NothingToUndo;
if isRoi then
RestoreRoi;
end;
end;
procedure DoResliceOptions;
var
default, tmp: extended;
Canceled: boolean;
prompt: str255;
begin
with info^.StackInfo^, info^ do begin
if SliceSpacing = 0.0 then
default := 1.0
else begin
if SpatiallyCalibrated then
default := SliceSpacing / xSpatialScale
else
default := SliceSpacing;
end;
tmp := GetReal(concat('Slice Spacing(', xUnit, '):'), default, Canceled);
if not Canceled and (tmp > 0.0) then begin
if SpatiallyCalibrated then
SliceSpacing := tmp * xSpatialScale
else
SliceSpacing := tmp;
end;
end;
end;
procedure GetSlice (xstart, ystart, start: real; angle: extended; count: integer; var line: LineType);
var
i: integer;
x, y, xinc, yinc: extended;
IntegerStart: boolean;
begin
IntegerStart := (xstart = trunc(xstart)) and (ystart = trunc(ystart));
if IntegerStart and (angle = 0.0) then begin
GetLine(trunc(xstart), trunc(ystart), count, line);
exit(GetSlice);
end;
if IntegerStart and (angle = 270.0) then begin
GetColumn(trunc(xstart), trunc(ystart), count, line);
exit(GetSlice);
end;
angle := (angle / 180.0) * pi;
xinc := cos(angle);
yinc := -sin(angle);
x := xstart + start * xinc;
y := ystart + start * yinc;
for i := 0 to count - 1 do begin
line[i] := round(GetInterpolatedPixel(x, y));
x := x + xinc;
y := y + yinc;
end;
end;
procedure Reslice;
var
DstWidth, DstHeight, nSlices: integer;
dstLeft, dstTop, y, i, j, LineLength: integer;
SaveWindowFlag, SaveMacro, HorizontalMode: boolean;
SaveHScale, SaveVScale, UncalibratedLineLength, CalibratedLineLength, angle: extended;
Stack, Reconstruction: InfoPtr;
aLine: LineType;
name, str1, str2: str255;
MaskRect: rect;
x1, y1, x2, y2, ulength, clength: real;
procedure MakeRoi (Left, Top, Width, Height: integer);
begin
with info^ do begin
RoiType := RectRoi;
SetRect(RoiRect, left, top, left + width, top + height);
MakeRegion;
SetupUndo;
RoiShowing := true;
end;
end;
begin
with info^, info^.StackInfo^ do begin
if nSlices < 2 then begin
PutMessage('Reslicing requires at least 2 slices.');
macro := false;
exit(Reslice);
end;
if not (RoiShowing and (RoiType = LineRoi)) then begin
PutMessage('Please make a straight line selection first.');
macro := false;
exit(Reslice);
end;
Stack := info;
GetLengthOrPerimeter(ulength, clength);
LineLength := round(ulength);
if LineLength = 0 then begin
PutMessage('Line length cannot be zero.');
macro := false;
exit(Reslice);
end;
if SliceSpacing = 0.0 then
DoResliceOptions;
GetLoi(x1, y1, x2, y2);
if (LAngle = 0.0) or (LAngle = 270.0) then
if NotInBounds then
exit(Reslice);
HorizontalMode := not OptionKeyWasDown;
if HorizontalMode then begin
DstWidth := round(LineLength);
DstHeight := round(nSlices * SliceSpacing);
if DstHeight < nSlices then
DstHeight := nSlices;
dstLeft := 0;
dstTop := round((dstHeight - nSlices) / 2);
end
else begin
DstWidth := round(nSlices * SliceSpacing);
if DstWidth < nSlices then
DstWidth := nSlices;
DstHeight := round(LineLength);
dstLeft := round((dstWidth - nSlices) / 2);
dstTop := 0;
end;
RealToString(y1, 3, 0, str1);
RealToString(LAngle, 1, 2, str2);
name := concat(str1, '-', str2);
if not NewPicWindow(name, DstWidth, DstHeight) then
exit(Reslice);
Reconstruction := info;
SaveWindowFlag := rsCreateNewWindow;
SaveHScale := rsHScale;
SaveVScale := rsVScale;
rsCreateNewWindow := false;
rsMethod := bilinear;
for i := 1 to nSlices do begin
Info := Stack;
SelectSlice(i);
GetSlice(x1, y1, 0.0, LAngle, LineLength, aLine);
info := Reconstruction;
if HorizontalMode then begin
PutLine(dstLeft, dstTop + nSlices - i, LineLength, aLine);
if i = 1 then {Draw extra line needed to get scaling to work right.}
PutLine(dstLeft, dstTop + nSlices, LineLength, aLine);
SetRect(MaskRect, dstLeft, dstTop + nSlices - i, dstLeft + LineLength, dstTop + nSlices - i + 1);
end
else begin
PutColumn(dstLeft + nSlices - i, dstTop, LineLength, aLine);
if i = 1 then {Draw extra line needed to get scaling to work right.}
PutLine(dstLeft + nSlices, dstTop, LineLength, aLine);
SetRect(MaskRect, dstLeft + nSlices - i, dstTop, dstLeft + nSlices - i + 1, dstTop + LineLength);
end;
UpdateScreen(MaskRect);
end;
if HorizontalMode then begin
MakeRoi(dstLeft, dstTop, LineLength, nSlices);
rsHScale := 1.0;
rsVScale := SliceSpacing;
end
else begin
MakeRoi(dstLeft, dstTop, nSlices, LineLength);
rsHScale := SliceSpacing;
rsVScale := 1.0;
end;
rsAngle := 0;
SaveMacro := macro;
macro := true;
ScaleAndRotate;
macro := SaveMacro;
Info := Stack;
SelectSlice(CurrentSlice);
Info := Reconstruction;
rsCreateNewWindow := SaveWindowFlag;
rsHScale := SaveHScale;
rsVScale := SaveVScale;
KillRoi;
end;
end;
procedure Animate;
var
n, SaveN, fpsInterval, DelayCount: integer;
Event: EventRecord;
ch: char;
b: boolean;
SingleStep, GoForward, NewKeyDown, PhotoMode: boolean;
nFrames, StartTicks, NextTicks, SaveTicks, ticks: LongInt;
fps, seconds: extended;
procedure ShowFPS (fps: extended);
var
hstart, vstart, ivalue: integer;
key: str255;
begin
if PhotoMode then
exit(ShowFPS);
hstart := ValuesHStart;
vstart := ValuesVStart;
SetPort(ValuesWindow);
MoveTo(xValueLoc, vstart);
case DelayTicks of
0:
key := '9 ';
2:
key := '8 ';
3:
key := '7 ';
4:
key := '6 ';
6:
key := '5 ';
8:
key := '4 ';
12:
key := '3 ';
30:
key := '2 ';
60:
key := '1 ';
end;
if SingleStep then begin
if GoForward then
key := '->'
else
key := '<-';
end;
DrawString(key);
MoveTo(yValueLoc, vstart + 10);
DrawReal(fps, 1, 2);
DrawChar(' ');
end;
begin
if info^.StackInfo = nil then begin
PutMessage('Animation requires a stack.');
exit(Animate);
end;
with info^, info^.StackInfo^ do begin
if nSlices < 2 then begin
PutMessage('Animation requires at least two "slices".');
exit(Animate);
end;
KillRoi;
PhotoMode := OptionKeyDown or OptionKeyWasDown;
if PhotoMode then
EraseScreen
else begin
ShowWatch;
ShowMessage(concat('Use 1...9 keys to control speed', cr, 'Use arrow keys to single step', cr, 'Press mouse button to stop'));
end;
FlushEvents(EveryEvent, 0);
fpsInterval := 10;
SaveN := -1;
n := 1;
GoForward := true;
SingleStep := false;
nFrames := 0;
StartTicks := TickCount;
NextTicks := StartTicks;
SaveTicks := StartTicks;
if not PhotoMode then begin
DrawLabels('key:', 'fps:', '');
SetPort(ValuesWindow);
TextSize(9);
TextFont(Monaco);
TextMode(SrcCopy);
end;
repeat
b := WaitNextEvent(EveryEvent, Event, 0, nil);
NewKeyDown := (event.what = KeyDown) or (event.what = AutoKey);
if NewKeyDown then begin
Ch := chr(BitAnd(Event.message, 127));
SingleStep := false;
case ord(ch) of
28, 44, 60, PageUp: {<-, <}
begin
SingleStep := true;
GoForward := false;
n := n - 1;
if n < 1 then
n := 1;
DelayTicks := 0
end; {left}
29, 46, 62, PageDown: {->, >}
begin
SingleStep := true;
GoForward := true;
n := n + 1;
if n > nSlices then
n := nSlices;
DelayTicks := 0
end; {right}
57:
DelayTicks := 0; {'9'-max speed}
56:
DelayTicks := 2; {'8'-30 fps}
55:
DelayTicks := 3; {'7'-20 fps}
54:
DelayTicks := 4; {'6'-15 fps}
53:
DelayTicks := 6; {'5'-10 fps}
52:
DelayTicks := 8; {'4'-7.5 fps}
51:
DelayTicks := 12; {'3'-5 fps}
50:
DelayTicks := 30; {'2'-2 fps}
49:
DelayTicks := 60; {'1'-1 fps}
otherwise
end; {case}
if DelayTicks > 12 then
fpsInterval := 2
else if DelayTicks > 3 then
fpsInterval := 5
else
fpsInterval := 10;
end; {if NewKeyDown}
if GoForward then begin
if not SingleStep then
n := n + 1;
if n > nSlices then begin
if OscillatingMovies then begin
n := nSlices - 1;
GoForward := false;
end
else
n := 1;
end;
end
else begin
if not SingleStep then
n := n - 1;
if n < 1 then begin
if OscillatingMovies then begin
n := 2;
Goforward := true;
end
else
n := nSlices;
end;
end;
CurrentSlice := n;
SelectSlice(CurrentSlice);
UpdatePicWindow;
nFrames := nFrames + 1;
if SingleStep then begin
if (not OptionKeyWasDown) and (n <> SaveN) then begin
UpdateTitleBar;
SaveN := n;
end;
ShowFPS(0.0);
end
else if (nFrames mod fpsInterval) = 0 then begin
ticks := TickCount;
seconds := (ticks - SaveTicks) / 60.0;
if seconds <> 0.0 then
fps := fpsInterval / seconds
else
fps := 0.0;
ShowFPS(fps);
SaveTicks := ticks;
end;
DelayCount := 0;
if DelayTicks > 0 then begin
repeat
ticks := TickCount;
until ticks >= NextTicks;
NextTicks := ticks + DelayTicks;
end;
until (event.what = MouseDown) or (event.what = osEvt);
if PhotoMode then
RestoreScreen;
FlushEvents(EveryEvent, 0);
end; {with}
end;
procedure MakeMovie;
var
nFrames, wleft, wtop, width, height, frame, i: integer;
ignore, SaveFW: integer;
OutOfMemory: boolean;
DisplayPoint: point;
StartTicks, NextTicks, interval, ElapsedTime: LongInt;
SecondsBetweenFrames, seconds: extended;
frect: rect;
MainDevice: GDHandle;
SourcePixMap: PixMapHandle;
str1, str2, str3: str255;
Canceled: boolean;
begin
with info^ do begin
if (PictureType <> FrameGrabberType) and (PictureType <> ScionType) then begin
PutMessage('You must be capturing to make a movie.');
exit(MakeMovie);
end;
StopDigitizing;
if not (RoiShowing and (RoiType = RectRoi)) then begin
PutMessage('Please make a rectangular selection first.');
exit(MakeMovie);
end;
if NotInBounds then
exit(MakeMovie);
SaveFW := FramesWanted;
FramesWanted := GetInt('Number of Frames:', FramesWanted, Canceled);
if Canceled then begin
FramesWanted := SaveFW;
exit(MakeMovie);
end;
if FramesWanted < 1 then
FramesWanted := 1;
if FramesWanted > MaxSlices then
FramesWanted := MaxSlices;
with RoiRect do begin
left := band(left + 1, $fffc); {Word align}
right := band(right + 2, $fffc);
if right > PicRect.right then
right := PicRect.right;
MakeRegion;
wleft := left;
wtop := top;
width := right - left;
height := bottom - top;
end;
end; {with info^}
if FrameGrabber = Scion then begin
with DisplayPoint do begin
h := PicLeftBase;
v := PicTopBase;
end;
with frect do begin
left := PicLeftBase + wleft;
top := PicTopBase + wtop;
right := left + width;
bottom := top + height;
end;
end
else
with frect do begin
left := wleft;
top := wtop;
right := left + width;
bottom := top + height;
end;
if not NewPicWindow('Movie', width, height) then
exit(MakeMovie);
if not MakeStackFromWindow then
exit(MakeMovie);
nFrames := 1;
OutOfMemory := false;
while (nFrames < FramesWanted) and (not OutOfMemory) do begin
OutOfMemory := not AddSlice(false);
if not OutOfMemory then
nFrames := nFrames + 1;
end;
if ExternalTrigger then
SecondsBetweenFrames := 0.0
else
SecondsBetweenFrames := GetReal('Delay Between Frames(seconds):', 0.0, Canceled);
if Canceled then
with info^ do begin
changes := false;
ignore := CloseAWindow(wptr);
Exit(MakeMovie);
end;
if SecondsBetweenFrames < 0.0 then
SecondsBetweenFrames := 0.0;
interval := round(60.0 * SecondsBetweenFrames);
if FrameGrabber = Scion then begin
HideCursor;
MainDevice := GetMainDevice;
SourcePixMap := MainDevice^^.gdPMap;
end
else begin
ShowWatch;
SourcePixMap := fgPort^.portPixMap;
ResetFrameGrabber;
end;
ShowTriggerMessage;
StartTicks := TickCount;
NextTicks := StartTicks;
with info^, info^.StackInfo^ do begin
if Interval >= 30 then
ShowMessage(CmdPeriodToStop)
else
DrawLabels('Frame:', 'Total:', '');
for frame := 1 to nFrames do begin
CurrentSlice := frame;
SelectSlice(CurrentSlice);
NextTicks := NextTicks + Interval;
if FrameGrabber = Scion then begin
GetScionFrame(DisplayPoint);
CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
end
else begin
if Interval >= 30 then
UpdateTitleBar
else
Show2Values(CurrentSlice, nSlices);
GetFrame;
CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
if not BlindMovieCapture then
UpdatePicWindow;
end;
while TickCount < NextTicks do
if CommandPeriod then begin
beep;
wait(60);
exit(MakeMovie);
end;
end; {for}
seconds := (TickCount - StartTicks) / 60.0;
LoopTime := seconds;
end; {with}
RealToString(seconds, 1, 2, str1);
str1 := concat(long2str(nFrames), ' frames', cr, str1, ' seconds', cr);
RealToString(seconds / nFrames, 1, 3, str2);
str3 := concat(str1, str2, ' seconds/frame', cr);
if nFrames >= seconds then
ShowFrameRate(str3, StartTicks, nFrames)
else
ShowMessage(str3);
ShowFirstOrLastSlice(HomeKey);
end;
procedure CaptureFrames;
var
nFrames, wleft, wtop, width, height, i: integer;
ignore, SaveFW: integer;
OutOfMemory, AdvanceFrame, b: boolean;
DisplayPoint: point;
frect: rect;
MainDevice: GDHandle;
SourcePixMap: PixMapHandle;
Event: EventRecord;
ShutterSound: handle;
err: OSErr;
procedure CheckButton;
begin
if Button and not AdvanceFrame then
with Info^.StackInfo^ do begin
AdvanceFrame := true;
ShutterSound := GetResource('snd ', 100);
if ShutterSound <> nil then
err := SndPlay(nil, ShutterSound, false);
if CurrentSlice < nSlices then begin
CurrentSlice := CurrentSlice + 1;
UpdateTitleBar;
CurrentSlice := CurrentSlice - 1;
end;
end;
end;
begin
with info^ do begin
if (PictureType <> FrameGrabberType) and (PictureType <> ScionType) then begin
PutMessage('You must be capturing to capture frames.');
exit(CaptureFrames);
end;
StopDigitizing;
if not (RoiShowing and (RoiType = RectRoi)) then begin
PutMessage('Please make a rectangular selection first.');
exit(CaptureFrames);
end;
if NotInBounds then
exit(CaptureFrames);
SaveFW := FramesWanted;
ShutterSound := nil;
with RoiRect do begin
left := band(left + 1, $fffc); {Word align}
right := band(right + 2, $fffc);
if right > PicRect.right then
right := PicRect.right;
MakeRegion;
wleft := left;
wtop := top;
width := right - left;
height := bottom - top;
end;
end; {with info^}
if FrameGrabber = Scion then begin
with DisplayPoint do begin
h := PicLeftBase;
v := PicTopBase;
end;
with frect do begin
left := PicLeftBase + wleft;
top := PicTopBase + wtop;
right := left + width;
bottom := top + height;
end;
end
else
with frect do begin
left := wleft;
top := wtop;
right := left + width;
bottom := top + height;
end;
if not NewPicWindow('Frames', width, height) then
exit(CaptureFrames);
if not MakeStackFromWindow then
exit(CaptureFrames);
UpdateTitleBar;
if FrameGrabber = Scion then begin
HideCursor;
MainDevice := GetMainDevice;
SourcePixMap := MainDevice^^.gdPMap;
end
else begin
ShowWatch;
SourcePixMap := fgPort^.portPixMap;
ResetFrameGrabber;
end;
FlushEvents(EveryEvent, 0);
ExternalTrigger := false;
UpdateVideoControl;
with info^, info^.StackInfo^ do begin
ShowMessage(CmdPeriodToStop);
OutOfMemory := false;
AdvanceFrame := false;
while (not OutOfMemory) and (CurrentSlice <= MaxSlices) do begin
if AdvanceFrame then begin
OutOfMemory := not AddSlice(false);
AdvanceFrame := false;
end;
if FrameGrabber = Scion then begin
GetScionFrame(DisplayPoint);
CheckButton;
CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
CheckButton;
end
else begin
GetFrame;
CheckButton;
CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
CheckButton;
UpdatePicWindow;
CheckButton;
end;
b := WaitNextEvent(EveryEvent, Event, 0, nil);
if event.what = KeyDown then
leave;
end; {while}
end; {with}
if ShutterSound <> nil then
ReleaseResource(ShutterSound);
end;
procedure CopyPics (sPort, dPort: cGrafPtr; sRect, dRect: rect);
begin
pmForeColor(BlackIndex);
pmBackColor(WhiteIndex);
hlock(handle(sPort^.portPixMap));
hlock(handle(dPort^.portPixMap));
CopyBits(BitMapHandle(sPort^.portPixMap)^^, BitMapHandle(dPort^.PortPixMap)^^, sRect, dRect, SrcCopy, nil);
hunlock(handle(sPort^.portPixMap));
hunlock(handle(dPort^.PortPixMap));
pmForeColor(ForegroundIndex);
pmBackColor(BackgroundIndex);
end;
procedure MakeMontage;
{Opens a new window and creates a composite image}
{from the slices in the current stack.}
const
ColumnsID = 3;
RowsID = 4;
ScaleID = 5;
FirstID = 6;
LastID = 7;
IncrementID = 8;
NumberID = 9;
var
mylog: DialogPtr;
item, i, nRows, nColumns, Inc, slices: integer;
StackWidth, StackHeight, mWidth, mHeight, Background: integer;
dWidth, dHeight, dLeft, dTop, dRight, dBottom, MaxWidth, MaxHeight: integer;
FirstSlice, LastSlice, TotalSlices: integer;
scale, SaveScale: extended;
sPort, dPort: cGrafPtr;
StackInfo, MontageInfo: InfoPtr;
sRect, dRect: rect;
NumberSlices, IncrementSet: boolean;
str: str255;
loc: point;
procedure Estimate (adjustinc: boolean);
var
tmp, xScale, yScale: extended;
n: integer;
begin
slices := LastSlice - FirstSlice + 1;
if adjustinc then
inc := 0;
repeat
if adjustinc then
inc := inc + 1;
n := trunc(slices / inc);
tmp := sqrt(n);
if trunc(tmp) <> tmp then
tmp := trunc(tmp) + 1.0;
nColumns := trunc(tmp);
nRows := nColumns;
if (nColumns * (nRows - 1)) >= n then
nRows := nRows - 1;
xScale := (MaxWidth / nColumns) / StackWidth;
yScale := (MaxHeight / nRows) / StackHeight;
if xScale < yScale then
scale := xScale
else
scale := yScale;
if scale > 1.0 then
scale := 1.0;
SaveScale := scale;
until (scale >= 0.5) or (inc >= 3) or not adjustinc;
end;
begin
InitCursor;
with info^ do begin
StackWidth := PixelsPerLine;
StackHeight := nLines;
FirstSlice := 1;
TotalSlices := StackInfo^.nSlices;
LastSlice := TotalSlices;
end;
MaxWidth := ScreenWidth - 85;
MaxHeight := ScreenHeight - 45;
Estimate(true);
NumberSlices := true;
IncrementSet := false;
mylog := GetNewDialog(150, nil, pointer(-1));
SetDNum(MyLog, RowsID, nRows);
SetDNum(MyLog, ColumnsID, nColumns);
SetDReal(MyLog, ScaleID, scale, 2);
SetDNum(MyLog, FirstID, FirstSlice);
SetDNum(MyLog, LastID, LastSlice);
SetDNum(MyLog, IncrementID, inc);
SetDialogItem(MyLog, NumberID, ord(NumberSlices));
OutlineButton(MyLog, ok, 16);
repeat
ModalDialog(nil, item);
if item = ColumnsID then begin
nColumns := GetDNum(MyLog, ColumnsID);
if nColumns < 0 then begin
nColumns := 0;
SetDNum(MyLog, ColumnsID, nRows);
end;
end;
if item = RowsID then begin
nRows := GetDNum(MyLog, RowsID);
if nRows < 0 then begin
nRows := 0;
SetDNum(MyLog, RowsID, nRows);
end;
end;
if item = ScaleID then
scale := GetDReal(MyLog, ScaleID);
if item = FirstID then begin
FirstSlice := GetDNum(MyLog, FirstID);
if (FirstSlice < 1) or (FirstSlice > LastSlice) then
FirstSlice := 1;
if IncrementSet then
Estimate(false)
else
Estimate(true);
SetDNum(MyLog, RowsID, nRows);
SetDNum(MyLog, ColumnsID, nColumns);
SetDReal(MyLog, ScaleID, scale, 2);
end;
if item = LastID then begin
LastSlice := GetDNum(MyLog, LastID);
if (LastSlice < FirstSlice) or (LastSlice > TotalSlices) then
LastSlice := TotalSlices;
if IncrementSet then
Estimate(false)
else
Estimate(true);
SetDNum(MyLog, RowsID, nRows);
SetDNum(MyLog, ColumnsID, nColumns);
SetDReal(MyLog, ScaleID, scale, 2);
end;
if item = IncrementID then begin
inc := GetDNum(MyLog, IncrementID);
IncrementSet := true;
if (inc < 1) or (inc > (slices div 2)) then begin
inc := 1;
SetDNum(MyLog, IncrementID, inc);
end;
Estimate(false);
SetDNum(MyLog, RowsID, nRows);
SetDNum(MyLog, ColumnsID, nColumns);
SetDReal(MyLog, ScaleID, scale, 2);
end;
if item = NumberID then begin
NumberSlices := not NumberSlices;
SetDialogItem(MyLog, NumberID, ord(NumberSlices));
end;
until (item = ok) or (item = cancel);
DisposDialog(mylog);
if item = cancel then
exit(MakeMontage);
if (scale <= 0.05) or (scale > 5) then
scale := SaveScale;
dWidth := round(StackWidth * scale);
dHeight := round(StackHeight * scale);
mWidth := nColumns * dWidth;
mHeight := nRows * dHeight;
StackInfo := info;
Background := MyGetPixel(0, 0);
SetBackgroundColor(Background);
if Background = WhiteIndex then
SetForegroundColor(BlackIndex)
else
SetForegroundColor(WhiteIndex);
if not NewPicWindow('Montage', mWidth, mHeight) then
exit(MakeMontage);
MontageInfo := info;
if NumberSlices then begin
SetPort(GrafPtr(info^.osPort));
pmForeColor(ForegroundIndex);
TextFont(ApplFont);
TextSize(9);
end;
dPort := info^.osPort;
dLeft := 0;
dTop := 0;
sPort := StackInfo^.osPort;
sRect := StackInfo^.PicRect;
i := FirstSlice;
while i <= LastSlice do begin
Info := StackInfo;
SelectSlice(i);
SetRect(dRect, dLeft, dTop, dLeft + dWidth, dTop + DHeight);
CopyPics(sPort, dPort, sRect, dRect);
info := MontageInfo;
if NumberSlices then begin
MoveTo(dLeft + (dWidth div 2) - 3, dTop + dHeight - 9);
NumToString(i, str);
loc.h := dLeft + (dWidth div 2) - 3;
loc.v := dTop + dHeight - 5;
DrawTextString(str, loc, TeJustCenter);
end;
UpdateScreen(dRect);
dLeft := dLeft + dWidth;
if (dLeft + dWidth) > mWidth then begin
dLeft := 0;
dTop := dTop + dHeight;
end;
i := i + inc;
end;
info := StackInfo;
SelectSlice(info^.StackInfo^.CurrentSlice);
if MontageInfo^.PixMapSize > UndoBufSize then
PutWarning;
end;
procedure CopyRGBToPixMap (pmap: PixMapHandle);
type
LongPtr = ^LongInt;
var
row, i, width: integer;
RedLine, GreenLine, BlueLine: LineType;
Pixel, RowOffset: LongInt;
pmapPtr: ptr;
LPtr, RowStart: LongPtr;
begin
with info^ do begin
pmapPtr := GetPixBaseAddr(pmap);
if pmapPtr = nil then
exit(CopyRGBToPixMap);
LPtr := LongPtr(pmapPtr);
RowStart := LPtr;
RowOffset := band(pmap^^.RowBytes, $1FFF);
width := PicRect.right;
for row := 0 to nLines - 1 do begin
SelectSlice(1);
GetLine(0, row, width, RedLine);
SelectSlice(2);
GetLine(0, row, width, GreenLine);
SelectSlice(3);
GetLine(0, row, width, BlueLine);
LPtr := RowStart;
for i := 0 to PixelsPerLine - 1 do begin
pixel := -1;
pixel := RedLine[i];
pixel := bor(bsl(pixel, 8), GreenLine[i]);
pixel := bor(bsl(pixel, 8), blueLine[i]);
LPtr^ := BitNot(pixel);
LPtr := LongPtr(ord4(LPtr) + 4);
end;
RowStart := LongPtr(ord4(RowStart) + RowOffset);
end;
SelectSlice(StackInfo^.CurrentSlice);
end; {with}
end;
function DoColorOptions: boolean;
const
ExistingID = 4;
SystemID = 5;
CustomID = 6;
DitherID = 7;
var
mylog: DialogPtr;
item: integer;
procedure UpdateButtons;
begin
SetDialogItem(mylog, ExistingID, ord(RGBLut = ExistingLUT));
SetDialogItem(mylog, SystemID, ord(RGBLut = SystemLUT));
SetDialogItem(mylog, CustomID, ord(RGBLut = CustomLUT));
end;
begin
InitCursor;
mylog := GetNewDialog(160, nil, pointer(-1));
SetDialogItem(mylog, DitherID, ord(DitherColor));
UpdateButtons;
OutlineButton(MyLog, ok, 16);
repeat
ModalDialog(nil, item);
if item = DitherID then begin
DitherColor := not DitherColor;
SetDialogItem(mylog, DitherID, ord(DitherColor));
end;
if item = ExistingID then begin
RGBLut := ExistingLUT;
UpdateButtons
end;
if item = SystemID then begin
RGBLut := SystemLUT;
UpdateButtons;
DitherColor := true;
SetDialogItem(mylog, DitherID, ord(DitherColor));
end;
if item = CustomID then begin
RGBLut := CustomLUT;
UpdateButtons
end;
until (item = ok) or (item = cancel);
DisposDialog(mylog);
DoColorOptions := item <> cancel;
end;
function Activate (name: str255): boolean;
{Activates the window with the specified name.}
var
i: integer;
TempInfo: InfoPtr;
begin
Activate := false;
for i := 1 to nPics do begin
TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
if TempInfo^.title = name then begin
if PicWindow[i] <> nil then begin
SelectWindow(PicWindow[i]);
Info := TempInfo;
ActivateWindow;
Activate := true;
end; {if}
leave;
end; {if}
end; {for}
end;
procedure ConvertRGBToEightBitColor (Capturing: boolean);
var
err: QDErr;
err2: OSErr;
osGWorld: GWorldPtr;
aGDevice: GDHandle;
flags: GWorldFlags;
pmap: PixMapHandle;
pRect: rect;
thePictInfo: PictInfo;
CopyMode, SamplingMethod: integer;
UpdateNeeded: boolean;
procedure abort;
begin
DisposeGWorld(osGWorld);
exit(ConvertRGBToEightBitColor);
end;
begin
if not System7 then begin
PutMessage('You must be running System 7 to do 24 to 8-bit color conversions.');
exit(ConvertRGBToEightBitColor);
end;
with info^ do begin
if StackInfo^.nSlices <> 3 then begin
PutMessage('24 to 8-bit color conversion requires a three slice(red, green and blue) stack as input.');
exit(ConvertRGBToEightBitColor);
end;
if Capturing then begin
DitherColor := true;
RGBLut := CustomLUT;
end
else if not macro then begin
if not DoColorOptions then
exit(ConvertRGBToEightBitColor);
end;
ShowWatch;
flags := [];
err := NewGWorld(osGWorld, 32, PicRect, nil, aGDevice, flags);
if err <> NoErr then begin
PutMemoryAlert;
exit(ConvertRGBToEightBitColor);
end;
pmap := GetGWorldPixMap(osGWorld);
if not LockPixels(pmap) then
abort;
CopyRGBToPixMap(pmap);
pRect := PicRect;
end; {with}
UpdateNeeded := true;
if Activate('Indexed Color') then begin
if (info^.PixelsPerLine <> pRect.right) or (info^.nLines <> pRect.bottom) then begin
if not NewPicWindow('Indexed Color', pRect.right, pRect.bottom) then
abort;
UpdateNeeded := false;
end
end
else begin
if not NewPicWindow('Indexed Color', pRect.right, pRect.bottom) then
abort;
UpdateNeeded := false;
end;
if RGBLut = SystemLUT then
SwitchColorTables(SystemPaletteItem, false)
else if RGBLut = CustomLut then begin
if OptionKeyWasDown then
SamplingMethod := PopularMethod
else
SamplingMethod := SystemMethod;
err2 := GetPixMapInfo(pmap, thePictInfo, ReturnColorTable, 256, SamplingMethod, 0);
LoadColorTable(thePictInfo.theColorTable);
end;
SetForegroundColor(BlackIndex);
SetBackgroundColor(WhiteIndex);
if DitherColor then
CopyMode := DitherCopy
else
CopyMode := SrcCopy;
CopyBits(BitMapHandle(pmap)^^, BitMapHandle(info^.osPort^.PortPixMap)^^, pRect, pRect, CopyMode, nil);
DisposeGWorld(osGWorld);
if UpdateNeeded then
UpdatePicWindow;
end;
function MakeRGBStack (name: str255): boolean;
var
ignore: integer;
begin
MakeRGBStack := false;
if not Duplicate(name, false) then
exit(MakeRGBStack);
if not MakeStackFromWindow then
exit(MakeRGBStack);
if not AddSlice(false) then begin
info^.changes := false;
ignore := CloseAWindow(info^.wptr);
exit(MakeRGBStack);
end;
if not AddSlice(false) then begin
info^.changes := false;
ignore := CloseAWindow(info^.wptr);
exit(MakeRGBStack);
end;
MakeRGBStack := true;
end;
procedure ConvertEightBitColorToRGB;
var
width, height, i, row: integer;
srcLine, rLine, gLine, bLine: LineType;
rLut, gLUT, bLUT: packed array[0..255] of byte;
value: byte;
begin
if isGrayscaleLUT then begin
PutMessage('8-bit color to RGB conversion requires a color image.');
exit(ConvertEightBitColorToRGB);
end;
KillRoi;
if not MakeRGBStack(concat(info^.title, '(RGB)')) then
exit(ConvertEightBitColorToRGB);
LoadLUT(Info^.cTable);
for i := 0 to 255 do
with cScreenPort^.portPixMap^^.pmTable^^.ctTable[i].rgb do begin
rLUT[i] := BitNot(band(bsr(red, 8), 255));
gLUT[i] := BitNot(band(bsr(green, 8), 255));
bLUT[i] := BitNot(band(bsr(blue, 8), 255));
end;
width := info^.PixelsPerLine;
height := info^.nLines;
for row := 0 to height - 1 do begin
SelectSlice(1);
GetLine(0, row, width, srcLine);
for i := 0 to width - 1 do begin
value := srcLine[i];
rLine[i] := rLUT[value];
gLine[i] := gLUT[value];
bLine[i] := bLUT[value];
end;
PutLine(0, row, width, rLine);
SelectSlice(2);
PutLine(0, row, width, gLine);
SelectSlice(3);
PutLine(0, row, width, bLine);
end;
with Info^.StackInfo^ do begin
CurrentSlice := 1;
SelectSlice(CurrentSlice);
UpdateTitleBar;
end;
end;
procedure CaptureColor;
var
MainDevice: GDHandle;
SourcePixMap: PixMapHandle;
frame, width, height, SaveChannel: integer;
frect: rect;
DisplayPoint: point;
begin
with info^ do
if (PictureType <> FrameGrabberType) and (PictureType <> ScionType) then begin
PutMessage('You must be capturing to capture color.');
macro := false;
exit(CaptureColor);
end;
StopDigitizing;
with info^.PicRect do begin
width := right - left;
height := bottom - top;
end;
if Activate('RGB') then
with info^.PicRect do begin
if ((right - left) <> width) or ((bottom - top) <> height) then
if not MakeRGBStack('RGB') then
exit(CaptureColor);
end
else if not MakeRGBStack('RGB') then
exit(CaptureColor);
if FrameGrabber = Scion then begin
HideCursor;
MainDevice := GetMainDevice;
SourcePixMap := MainDevice^^.gdPMap;
end
else begin
ShowWatch;
SourcePixMap := fgPort^.portPixMap;
ResetFrameGrabber;
end;
if FrameGrabber = Scion then begin
with DisplayPoint do begin
h := PicLeftBase;
v := PicTopBase;
end;
with frect do begin
left := PicLeftBase;
top := PicTopBase;
right := left + width;
bottom := top + height;
end;
end
else
with frect do begin
left := 0;
top := 0;
right := left + width;
bottom := top + height;
end;
ShowTriggerMessage;
SaveChannel := VideoChannel;
with info^, info^.StackInfo^ do begin
for frame := 1 to 3 do begin
if FrameGrabber = QuickCapture then begin
case frame of
1:
VideoChannel := 1; {Green}
2:
VideoChannel := 0; {Red}
3:
VideoChannel := 2; {Blue}
end;
ResetFrameGrabber;
repeat
until band(ControlReg^, $8) = 0; {mux channel not busy}
end
else begin
VideoChannel := frame - 1;
ResetFrameGrabber;
end;
if VideoControl <> nil then
ShowChannel;
CurrentSlice := frame;
SelectSlice(CurrentSlice);
if FrameGrabber = Scion then begin
GetScionFrame(DisplayPoint);
CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
end
else begin
GetFrame;
CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, PicRect);
end;
end; {for}
CurrentSlice := 1;
SelectSlice(CurrentSlice);
UpdateTitleBar;
end; {with}
VideoChannel := SaveChannel;
if VideoControl <> nil then
ShowChannel;
ConvertRGBToEightBitColor(true);
end;
procedure AverageSlices;
const
MaxWidth = 2048;
var
slices, sRow, aRow, slice, i, SaveSlice: integer;
width, height, hstart, vStart: integer;
OldInfo, NewInfo: InfoPtr;
aLine: LineType;
mask: rect;
sum: array[0..MaxWidth] of LongInt;
AutoSelectAll: boolean;
begin
OldInfo := Info;
with info^ do begin
if StackInfo = nil then begin
PutMessage('Average Slices requires a stack.');
macro := false;
exit(AverageSlices);
end;
AutoSelectAll := not Info^.RoiShowing;
if AutoSelectAll then
SelectAll(true);
with RoiRect do begin
hStart := left;
vStart := top;
width := right - left;
height := bottom - top;
end;
if width > MaxWidth then begin
PutMessage(concat('Image can''t average selections wider than ', Long2str(MaxWidth), ' pixels.'));
macro := false;
exit(AverageSlices);
end;
with StackInfo^ do begin
slices := StackInfo^.nSlices;
SaveSlice := CurrentSlice;
end;
if not NewPicWindow('Average', width, height) then begin
macro := false;
exit(AverageSlices);
end;
end;
info^.changes := true;
NewInfo := Info;
aRow := 0;
for sRow := vStart to vStart + height - 1 do begin
info := OldInfo;
for i := 0 to width - 1 do
sum[i] := 0;
for slice := 1 to slices do begin
SelectSlice(slice);
GetLine(hStart, sRow, width, aLine);
for i := 0 to width - 1 do
sum[i] := sum[i] + aLine[i];
end;
for i := 0 to width - 1 do
aLine[i] := sum[i] div slices;
info := NewInfo;
PutLine(0, aRow, width, aLine);
SetRect(mask, 0, aRow, width, aRow + 1);
aRow := aRow + 1;
UpdateScreen(mask);
if CommandPeriod then
leave;
end;
info := OldInfo;
SelectSlice(SaveSlice);
if AutoSelectAll then
KillRoi;
end;
procedure ConvertRGBToHSV;
const
MaxSaturation = 255;
MaxValue = 255;
var
width, height, i, row, mark: integer;
rLine, gLine, bLine, hLine, sLine, vLine: LineType;
delta, min, max, R, G, B, H, S, V: integer;
tmp: longint;
UpdateR: rect;
function Max3 (a, b, c: integer): integer;
var
TempMax: integer;
begin
if (a > b) then
TempMax := a
else
TempMax := b;
if (TempMax > c) then
Max3 := TempMax
else
Max3 := c;
end;
function Min3 (a, b, c: integer): integer;
var
TempMin: integer;
begin
if (a < b) then
TempMin := a
else
TempMin := b;
if (TempMin < c) then
Min3 := TempMin
else
Min3 := c;
end;
begin
with info^ do begin
if StackInfo^.nSlices <> 3 then begin
PutMessage('RGB to HSV color conversion requires a three slice(red, green and blue) stack as input.');
exit(ConvertRGBToHSV);
end;
if Changes then begin
if PutMessageWithCancel('RGB to HSV color conversion is undoable.') = cancel then
exit(ConvertRGBToHSV);
end;
KillRoi;
with StackInfo^ do begin
CurrentSlice := 1;
SelectSlice(CurrentSlice);
UpdatePicWindow;
end;
SwitchColorTables(SpectrumItem, true);
title := 'HSV';
UpdateTitleBar;
width := PixelsPerLine;
height := nLines;
mark := 0;
ShowWatch;
for row := 0 to height - 1 do begin
SelectSlice(1);
GetLine(0, row, width, rLine);
SelectSlice(2);
GetLine(0, row, width, gLine);
SelectSlice(3);
GetLine(0, row, width, bLine);
for i := 0 to width - 1 do begin
R := 255 - rLine[i];
G := 255 - gLine[i];
B := 255 - bLine[i];
max := Max3(R, G, B);
min := Min3(R, G, B);
V := max;
if max <> 0 then begin
tmp := 255 * (max - min);
S := (tmp + (tmp mod max)) div max; {adding '(tmp mod max)' simulate rounding}
end
else
S := 0;
if S = 0 then
H := 0 {undefined but, but select red }
else begin
delta := max - min;
if R = max then begin
tmp := 85 * (G - B);
H := tmp div delta;
end
else if G = max then begin
tmp := 85 * (B - R);
H := 170 + tmp div delta;
end
else if B = max then begin
tmp := 85 * (R - G);
H := 340 + tmp div delta;
end;
H := H div 2;
if H < 0 then
H := H + 255
end;
if H = 0 then
hLine[i] := 1
else
hLine[i] := H;
sLine[i] := S;
vLine[i] := 255 - V;
end;
SelectSlice(1);
PutLine(0, row, width, hLine);
if (row mod 10) = 0 then begin
setrect(UpdateR, 0, mark, width - 1, row);
mark := row;
UpdateScreen(UpdateR);
end;
SelectSlice(2);
PutLine(0, row, width, sLine);
SelectSlice(3);
PutLine(0, row, width, vLine);
end;
SelectSlice(1);
end; {with}
WhatToUndo := NothingToUndo;
end;
end.